
/****
 * Create by Omid Mehdizadeh
 * Copyright 2010, Omid Mehdizadeh
 * Based on JDiameter Open Source Project
 */

import java.util.Date;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.logging.ConsoleHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;

import mt.omid.jscap.PeerManager;
import mt.omid.jscap.SCAPCode;
import mt.omid.jscap.StackImpl;
import mt.omid.jscap.Tools;
import mt.omid.jscap.operaion.SCAPSession;
import mt.omid.jscap.operaion.SCAPSessionFactory;

import org.jdiameter.api.Answer;
import org.jdiameter.api.ApplicationId;
import org.jdiameter.api.AvpSet;
import org.jdiameter.api.EventListener;
import org.jdiameter.api.InternalException;
import org.jdiameter.api.Message;
import org.jdiameter.api.Mode;
import org.jdiameter.api.Request;
import org.jdiameter.api.Session;
import org.jdiameter.api.SessionFactory;
import org.jdiameter.api.Stack;
import org.jdiameter.api.StackManager;
import org.jdiameter.api.app.AppSession;
import org.jdiameter.api.cca.ClientCCASession;
import org.jdiameter.api.cca.ClientCCASessionListener;
import org.jdiameter.client.api.IContainer;
import org.jdiameter.client.impl.app.cca.ClientCCASessionImpl;
import org.jdiameter.client.impl.helpers.ExtensionPoint;
import org.jdiameter.client.impl.helpers.Loggers;
import org.jdiameter.client.impl.helpers.XMLConfiguration;
import org.jdiameter.client.impl.parser.MessageImpl;
import org.jdiameter.common.impl.app.AppSessionImpl;
import org.jdiameter.common.impl.app.cca.AppCCASessionImpl;
import org.slf4j.LoggerFactory;

import static org.jdiameter.api.Message.*;
import static org.jdiameter.api.Avp.*;
import static mt.omid.jscap.SCAPCode.*;


public class JSCAPTest
{
    private static String destRealm = "ccn.test";

    public static void sampleSyncSCAPACR()
    {
	try
	{
	    String msisdn = "989371029278";

	    // Create Stack 
	    Class diamClass = Class.forName( "mt.omid.jscap.StackImpl" );
	    Stack diam = ( Stack ) diamClass.newInstance();

	    initLogger( diam );
	    // StackManager.registerStack( diam );
	    // StackManager.deregisterStack( diam );

	    // Create Config
	    XMLConfiguration conf = new XMLConfiguration( "clientConf.xml" );

	    // Init Stack & Get Session Factory
	    SessionFactory fact = diam.init( conf );

	    //Start Diameter Stack
	    diam.start( Mode.ANY_PEER, 10, TimeUnit.SECONDS );

	    // Get New Session
	    Session session = fact.getNewSession();

	    // Create Request	    
	    Request req = session.createRequest( ACCOUNTING_REQUEST, ApplicationId
		    .createByAccAppId( 0 ), destRealm );
	    req.setProxiable( true );

	    // Replace Origin Host with SCAP format
	    req.getAvps().removeAvp( ORIGIN_HOST );
	    req.getAvps().removeAvp( ORIGIN_REALM );

	    req.getAvps().addAvp( ORIGIN_HOST,
		    diam.getMetaData().getLocalPeer().getUri().toString(), true, false, false );
	    req.getAvps().addAvp( ORIGIN_REALM, diam.getMetaData().getLocalPeer().getRealmName(),
		    true, false, false );

	    // Add Vendor Specific ID
	    AvpSet vndApp = req.getAvps().addGroupedAvp( VENDOR_SPECIFIC_APPLICATION_ID, true,
		    false );
	    vndApp.addAvp( VENDOR_ID, diam.getMetaData().getLocalPeer().getVendorId(), true, false,
		    true );
	    vndApp.addAvp( ACCT_APPLICATION_ID, diam.getMetaData().getLocalPeer()
		    .getCommonApplications().iterator().next().getAcctAppId(), true, false, true );

	    // Add Record Type AVP
	    req.getAvps().addAvp( ACC_RECORD_TYPE, RECORD_TYPE_EVENT, true, false );

	    // Add Record Number
	    req.getAvps().addAvp( ACC_RECORD_NUMBER, 0, true, false );

	    // Add Subscription ID AVP
	    AvpSet subId = req.getAvps().addGroupedAvp( SCAP_AVP_Subscription_Id,
		    ERICSSON_VENDOR_ID, true, false );
	    subId.addAvp( SCAP_AVP_Subscription_Id_Type, END_USER_MSISDN, ERICSSON_VENDOR_ID, true,
		    false );
	    subId.addAvp( SCAP_AVP_Subscription_Id_Data, msisdn, ERICSSON_VENDOR_ID, true, false,
		    false );

	    // Add Event-Timestamp
	    req.getAvps().addAvp( SCAP_AVP_Event_Timestamp, new Date(), ERICSSON_VENDOR_ID, true,
		    false );

	    // Add Requested Action
	    req.getAvps().addAvp( SCAP_AVP_Requested_Action, ACTION_DIRECT_DEBIT,
		    ERICSSON_VENDOR_ID, true, false );

	    // Add Requested Unit
	    AvpSet srvUnit = req.getAvps().addGroupedAvp( SCAP_AVP_Requested_Service_Unit,
		    ERICSSON_VENDOR_ID, true, false );
	    srvUnit
		    .addAvp( SCAP_AVP_Unit_Type, SERVICE_UNIT_EVENT, ERICSSON_VENDOR_ID, true,
			    false );
	    srvUnit.addGroupedAvp( SCAP_AVP_Unit_Value, ERICSSON_VENDOR_ID, true, false ).addAvp(
		    SCAP_AVP_Value_Digits, 10L, ERICSSON_VENDOR_ID, true, false );

	    // Add Service Parameter Info AVPs
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_SERVICE_PROVIDER_ID, "0" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TRAFFIC_CASE, "20" );

	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TELE_SERVICE_CODE, "65528" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_EXTENSION_NUMBER_1, "1" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_CALLED_PARTY_NUMBER, "8441" );

	    // Send Request
	    Future<Message> future = session.send( req );

	    // Get Response
	    Answer res = ( Answer ) future.get();

	    // Print Result
	    System.out.println( res.getResultCode().getInteger32() );

	    //	    Thread.sleep( 5000 );

	    diam.stop( 1, TimeUnit.SECONDS );

	}
	catch( ClassNotFoundException e )
	{
	    e.printStackTrace();
	}
	catch( InstantiationException e )
	{
	    e.printStackTrace();
	}
	catch( IllegalAccessException e )
	{
	    e.printStackTrace();
	}
	catch( Exception e )
	{
	    e.printStackTrace();
	}
    }

    public static void sampleAsyncSCAPACR()
    {
	try
	{
	    String msisdn = "989371029278";

	    // Create Stack 
	    Class diamClass = Class.forName( "mt.omid.jscap.StackImpl" );
	    Stack diam = ( Stack ) diamClass.newInstance();

	    initLogger( diam );
	    // StackManager.registerStack( diam );
	    // StackManager.deregisterStack( diam );

	    // Create Config
	    XMLConfiguration conf = new XMLConfiguration( "clientConf.xml" );

	    // Init Stack & Get Session Factory
	    SessionFactory fact = diam.init( conf );

	    //Start Diameter Stack
	    diam.start( Mode.ANY_PEER, 10, TimeUnit.SECONDS );

	    // Get New Session
	    Session session = fact.getNewSession();

	    // Create Request	    
	    Request req = session.createRequest( ACCOUNTING_REQUEST, ApplicationId
		    .createByAccAppId( 0 ), destRealm );
	    req.setProxiable( true );

	    // Replace Origin Host with SCAP format
	    req.getAvps().removeAvp( ORIGIN_HOST );
	    req.getAvps().removeAvp( ORIGIN_REALM );

	    req.getAvps().addAvp( ORIGIN_HOST,
		    diam.getMetaData().getLocalPeer().getUri().toString(), true, false, false );
	    req.getAvps().addAvp( ORIGIN_REALM, diam.getMetaData().getLocalPeer().getRealmName(),
		    true, false, false );

	    // Add Vendor Specific ID
	    AvpSet vndApp = req.getAvps().addGroupedAvp( VENDOR_SPECIFIC_APPLICATION_ID, true,
		    false );
	    vndApp.addAvp( VENDOR_ID, diam.getMetaData().getLocalPeer().getVendorId(), true, false,
		    true );
	    vndApp.addAvp( ACCT_APPLICATION_ID, diam.getMetaData().getLocalPeer()
		    .getCommonApplications().iterator().next().getAcctAppId(), true, false, true );

	    // Add Record Type AVP
	    req.getAvps().addAvp( ACC_RECORD_TYPE, RECORD_TYPE_EVENT, true, false );

	    // Add Record Number
	    req.getAvps().addAvp( ACC_RECORD_NUMBER, 0, true, false );

	    // Add Subscription ID AVP
	    AvpSet subId = req.getAvps().addGroupedAvp( SCAP_AVP_Subscription_Id,
		    ERICSSON_VENDOR_ID, true, false );
	    subId.addAvp( SCAP_AVP_Subscription_Id_Type, END_USER_MSISDN, ERICSSON_VENDOR_ID, true,
		    false );
	    subId.addAvp( SCAP_AVP_Subscription_Id_Data, msisdn, ERICSSON_VENDOR_ID, true, false,
		    false );

	    // Add Event-Timestamp
	    req.getAvps().addAvp( SCAP_AVP_Event_Timestamp, new Date(), ERICSSON_VENDOR_ID, true,
		    false );

	    // Add Requested Action
	    req.getAvps().addAvp( SCAP_AVP_Requested_Action, ACTION_DIRECT_DEBIT,
		    ERICSSON_VENDOR_ID, true, false );

	    // Add Requested Unit
	    AvpSet srvUnit = req.getAvps().addGroupedAvp( SCAP_AVP_Requested_Service_Unit,
		    ERICSSON_VENDOR_ID, true, false );
	    srvUnit
		    .addAvp( SCAP_AVP_Unit_Type, SERVICE_UNIT_EVENT, ERICSSON_VENDOR_ID, true,
			    false );
	    srvUnit.addGroupedAvp( SCAP_AVP_Unit_Value, ERICSSON_VENDOR_ID, true, false ).addAvp(
		    SCAP_AVP_Value_Digits, 10L, ERICSSON_VENDOR_ID, true, false );

	    // Add Service Parameter Info AVPs
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_SERVICE_PROVIDER_ID, "0" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TRAFFIC_CASE, "20" );

	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TELE_SERVICE_CODE, "65528" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_EXTENSION_NUMBER_1, "1" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_CALLED_PARTY_NUMBER, "8441" );

	    // Create listener
	    Answer response = null;
	    EventListener listener = new EventListener(){

		public void receivedSuccessMessage( Message request, Message answer )
		{
		    // response = ( Answer ) answer;
		    System.out.println( "receivedSuccessMessage:" + answer );
		}

		public void timeoutExpired( Message request )
		{
		    System.out.println( "TimedOut" );
		}
	    };

	    // Send request
	    session.send( req, listener );
	    System.out.println( "Sent asyncly" );

	    // diam.stop( 10, TimeUnit.SECONDS );

	}
	catch( Exception e )
	{
	    e.printStackTrace();
	}
    }

    public static void testChargingSession( IContainer stk, SessionFactory sf )
    {
	SCAPSessionFactory fact = ( SCAPSessionFactory ) sf;
	try
	{
	    SCAPSession session = fact.getSCAPSession( null, null );
	    Request req = session.createChargingSessionStartRequest( "989371029272", destRealm, SERVICE_UNIT_EVENT, 2 );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TELE_SERVICE_CODE, "65528" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_EXTENSION_NUMBER_1, "1" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_CALLED_PARTY_NUMBER, "8441" );
	    session.send( req );

	    try { Thread.sleep( 1000 ); } catch(Exception e) {}

	    req = session.createChargingSessionInterimRequest( "989371029272", destRealm, SERVICE_UNIT_EVENT, 5, 2 );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TELE_SERVICE_CODE, "65528" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_EXTENSION_NUMBER_1, "1" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_CALLED_PARTY_NUMBER, "8441" );
	    session.send( req );

	    try { Thread.sleep( 1000 ); } catch(Exception e) {}

	    req = session.createChargingSessionStopRequest( "989371029272", destRealm, SERVICE_UNIT_EVENT, 5 );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TELE_SERVICE_CODE, "65528" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_EXTENSION_NUMBER_1, "1" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_CALLED_PARTY_NUMBER, "8441" );
	    session.send( req );
	}
	catch( Exception e )
	{
	    e.printStackTrace();
	}

    }

    public static void testDirectDebit( IContainer stk, SessionFactory sf )
    {
	SCAPSessionFactory fact = ( SCAPSessionFactory ) sf;
	try
	{
	    SCAPSession session = fact.getSCAPSession( null, null );
	    Request req = session.createDirectDebitEventRequest( "989371029272", 2, destRealm );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_TELE_SERVICE_CODE, "65528" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_EXTENSION_NUMBER_1, "1" );
	    Tools.addServiceParamInfo( req, SRV_PRM_INF_CALLED_PARTY_NUMBER, "8441" );
	    session.send( req );
	}
	catch( Exception e )
	{
	    e.printStackTrace();
	}
    }
    
    public static void main( String args[] )
    {
	// sampleAsyncSCAPACR();
	String msisdn = "989371029278";

	try
	{
	    // Create Stack 
	    Class diamClass = Class.forName( "mt.omid.jscap.StackImpl" );
	    Stack diam = ( Stack ) diamClass.newInstance();

	    initLogger( diam );

	    // Create Config
	    XMLConfiguration conf = new XMLConfiguration( "clientConf.xml" );

	    // Init Stack & Get Session Factory
	    SessionFactory fact = diam.init( conf );

	    //Start Diameter Stack
	    diam.start( Mode.ANY_PEER, 10, TimeUnit.SECONDS );

	    // sampleSyncSCAPACR();
	    // sampleAsyncSCAPACR();
	    // testChargingSession( (IContainer) diam, fact );
	    testDirectDebit( ( IContainer ) diam, fact );
	    
	    // diam.stop( 8, TimeUnit.SECONDS );
	}
	catch( Exception e )
	{
	    e.printStackTrace();
	}
    }

    public static void initLogger( Stack stack )
    {
	// Logger logger = stack.getLogger();
	Logger logger = Logger.getLogger( "ss" );
	logger.setLevel( Level.ALL );
	// Logger.getLogger( Logger.GLOBAL_LOGGER_NAME ).getHandlers()
	Handler hndl[] = Logger.getLogger( "" ).getHandlers();

	for( int i = 0; i < hndl.length; i++ )
	{
	    hndl[ i ].setLevel( Level.FINEST );
	}

	Loggers.FSM.logger().setLevel( Level.FINEST );
	ConsoleHandler fh = new ConsoleHandler();
	fh.setLevel( Level.ALL );
	stack.getLogger().addHandler( fh );
	stack.getLogger().setUseParentHandlers( false );
    }
}
